package com.xlongwei.service;

import java.util.Date;

import org.noear.snack.ONode;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Init;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.annotation.Param;

import com.xlongwei.util.HolidayUtil;
import com.xlongwei.util.HolidayUtil.Holiday;
import com.xlongwei.util.ZhDate;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateRange;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.Week;
import cn.hutool.core.date.Zodiac;
import cn.hutool.core.util.StrUtil;

@Controller
@Mapping("service/datetime")
public class Datetime {
    @Init
    public void init() throws Exception {
        HolidayUtil.isholiday(DateUtil.date());
    }

    @Mapping
    public ONode datetime() {
        return new ONode().set("datetime", DateUtil.now());
    }

    @Mapping("isworkday")
    public ONode isworkday(@Param Date day) {
        ONode n = new ONode();
        n.set("isworkday", HolidayUtil.isworkday(day == null ? new Date() : day));
        return n;
    }

    @Mapping("nextworkday")
    public ONode nextworkday(@Param Date day, @Param boolean skipweekend) {
        ONode n = new ONode();
        n.set("nextworkday", DateUtil.formatDate(HolidayUtil.nextworkday(day == null ? new Date() : day, skipweekend)));
        return n;
    }

    @Mapping("offsetworkday")
    public ONode offsetworkday(@Param Date day, @Param int offset, @Param boolean skipweekend) {
        ONode n = new ONode();
        n.set("offsetworkday",
                DateUtil.formatDate(HolidayUtil.offsetworkday(day == null ? new Date() : day, offset, skipweekend)));
        return n;
    }

    @Mapping("holiday")
    public ONode holiday(@Param Date day, @Param String name, @Param String year) {
        ONode n = new ONode();
        day = day == null ? new Date() : day;
        year = StrUtil.isBlank(year) ? "" + DateUtil.year(day) : year;
        String plan = StrUtil.isBlank(name) ? null : HolidayUtil.plans.get(year + "." + name);
        if (plan == null) {
            String format = HolidayUtil.dateFormat.format(day);
            Integer flag = HolidayUtil.holidays.get(format);
            if (flag != null) {
                if (flag.intValue() > 0) {
                    name = HolidayUtil.nameOf(flag);
                    if (StrUtil.isNotBlank(name)) {
                        year = format.substring(0, 4);
                        if ("元旦节".equals(name) && "12".equals(format.substring(5, 7))) {
                            year = String.valueOf(Integer.parseInt(year) + 1);
                        }
                        plan = HolidayUtil.plans.get(year + "." + name);
                    }
                } else {
                    n.set("remark", HolidayUtil.nameOf(-flag) + "调班");
                    return n;
                }
            } else {
                Holiday guessHoliday = HolidayUtil.guessHoliday(day);
                if (null != guessHoliday) {
                    name = guessHoliday.name();
                }
            }
        }
        if (StrUtil.isNotBlank(name)) {
            n.set("year", year);
            n.set("holiday", name);
            n.set("remark", plan == null ? "" : plan);
        } else {
            String remark = HolidayUtil.guessRemark(day);
            if (StrUtil.isNotBlank(remark)) {
                n.set("remark", remark);
            }
        }
        return n;
    }

    @Mapping("convert")
    public ONode convert(@Param Date day, @Param int lunarYear, @Param int lunarMonth, @Param int lunarDay,
            @Param boolean isLeapMonth) {
        ONode n = new ONode();
        if (day != null) {
            ZhDate zhDate = ZhDate.fromDate(day);
            n.set("nongli", zhDate.toString());
            n.set("chinese", zhDate.chinese());
            n.set("ganzhi", zhDate.ganzhi());
            n.set("shengxiao", zhDate.shengxiao());
            n.set("lunarYear", zhDate.getLunarYear());
            n.set("lunarMonth", zhDate.getLunarMonth());
            n.set("lunarDay", zhDate.getLunarDay());
            n.set("isLeapMonth", zhDate.isLeapMonth());
        } else {
            if (ZhDate.validate(lunarYear, lunarMonth, lunarDay, isLeapMonth)) {
                ZhDate zhDate = new ZhDate(lunarYear, lunarMonth, lunarDay, isLeapMonth);
                day = zhDate.toDate();
                n.set("day", DateUtil.formatDate(day));
                n.set("chinese", zhDate.chinese());
                n.set("ganzhi", zhDate.ganzhi());
                n.set("shengxiao", zhDate.shengxiao());
                n.set("zodiac", Zodiac.getZodiac(day));
            } else {
                n.set("status", "农历日期不支持");
            }
        }
        return n;
    }

    @Mapping("info")
    public ONode info(@Param Date day) {
        ONode n = new ONode();
        day = day == null ? new Date() : day;
        n.set("isworkday", HolidayUtil.isworkday(day));
        n.set("isholiday", HolidayUtil.isholiday(day));
        Week week = cn.hutool.core.date.DateUtil.dayOfWeekEnum(day);
        n.set("week", week.getValue() == 1 ? 7 : week.getValue() - 1);
        n.set("isweekend", week == Week.SATURDAY || week == Week.SUNDAY);
        n.set("zodiac", Zodiac.getZodiac(day));
        n.setAll(convert(day, 0, 0, 0, false));
        n.setAll(holiday(day, null, null));
        return n;
    }

    @Mapping("calendar")
    public ONode calendar(@Param Date day) {
        ONode n = new ONode();
        day = day == null ? new Date() : day;
        DateRange dateRange = DateUtil.range(DateUtil.beginOfMonth(day), DateUtil.endOfMonth(day),
                DateField.DAY_OF_MONTH);
        while (dateRange.hasNext()) {
            Date infoDay = dateRange.next().toJdkDate();
            n.set(DateUtil.formatDate(infoDay), info(day));
        }
        return n;
    }

    @Mapping("workday")
    public ONode workday(@Param Date day, @Param String type, @Param boolean skipweekend, @Param int offset,
            @Param String name, @Param String year, @Param int lunarYear, @Param int lunarMonth, @Param int lunarDay,
            @Param boolean isLeapMonth) {
        day = day == null ? new Date() : day;
        switch (type) {
            case "isworkday":
                return isworkday(day);
            case "nextworkday":
                return nextworkday(day, skipweekend);
            case "offsetworkday":
                return offsetworkday(day, offset, skipweekend);
            case "holiday":
                return holiday(day, name, year);
            case "convert":
                return convert(day, lunarYear, lunarMonth, lunarDay, isLeapMonth);
            case "calendar":
                return calendar(day);
            default:
                return info(day);
        }
    }
}
